<?php

/**
 * Database management Class
 *
 * Singleton Class (however we cant use the singleon enforcer due to inheritance
 * issues)
 * 
 * @author Ben Rowe
 */
class DB extends SingletonEnforcer 
{
	/**
	 * Reference to the database connection
	 *
	 * @access private
	 * @var database connection reference
	 */
	var $_conn		= false;
	
	/**
	 * Stores the server name, or ip address
	 *
	 * @access private
	 * @var string
	 */
	var $_server	= false;
	
	/**
	 * Stores the username to open a authenticated connection
	 *
	 * @access private
	 * @var string
	 */
	var $_username;
	
	/**
	 * Stores the password to open a authenticated connection to the database
	 *
	 * @access private
	 * @var string
	 */
	var $_password;
	
	/**
	 * The database to query from
	 *
	 * @access private
	 * @var string
	 */
	var $_database;
	
	/**
	 * Stores the complete SQL to be executed
	 *
	 * @access private
	 * @var string
	 */
	var $_sql = false;
	
	/**
	 * Stores the prefix for table names
	 *
	 * @access private
	 * @var string
	 */
	var $_prefix;
	
	function DB($server = false, $username = null, $password = null, $database = null, $prefix = null)
	{
		if($server !== false) {
			// only store the details if they have been provided
			$this->storeDetails($server, $username, $password, $database, $prefix);
		}
	}
	
	/**
	 * Store the connection details to be used by the connect method
	 *
	 * @access public
	 * @param string $server
	 * @param string $username
	 * @param string $password
	 * @param string $database
	 * @param string $prefix
	 * @return boolean
	 */
	function storeDetails($server, $username, $password, $database, $prefix = null)
	{
		$this->_server		= $server;
		$this->_username	= $username;
		$this->_password	= $password;
		$this->_database	= $database;
		$this->_prefix		= $prefix;
		return true;
	}
	
	/**
	 * Validate the connection method properties
	 *
	 * @todo tighten the logic here
	 * @access private
	 * @return unknown
	 */
	function _checkDetails()
	{
		if($this->_server != false)
		{
			return true;
		}
		return false;
	}
	
	/**
	 * Connect to the database
	 *
	 * @access public
	 * @return boolean
	 */
	function connect()
	{
		// place holder function
		die('connect() not defined correctly');
	}
	
	/**
	 * Disconnect from the current database
	 * 
	 * @access public
	 * @return boolean
	 */
	function disconnect()
	{
		// place holder function
		die('disconnect() not defined correctly');
	}

	/**
	 * Set the sql query to be executed
	 * the table prefix is applied, and any optional arguments are parsed, and 
	 *
	 * 
	 * @param string $sql
	 * @param mixed[...] $undefined (unlimited arguments available!)
	 * @return boolean
	 */
	function setQuery()
	{
		$args = func_get_args();
		$sql = $this->_processArguments($args);
		if($sql !== false) {
			$this->_sql = $sql;
		}
		return false;
	}
	
	/**
	 * Run the currently provided query
	 *
	 * @access public
	 * @return DBResult
	 */
	function run()
	{
		// placeholder function. Must be declared in
		die('run() not defined correctly');
	}
	
	/**
	 * Escape the value to stop SQL injections
	 *
	 * @access private
	 * @param mixed $value
	 * @return mixed
	 */
	function escape($value)
	{
		return addslashes($value);
	}
	
	function _processArguments($args)
	{
		// define the marker types
		$float		= array('f');
		$integer	= array('u', 'd', 'b', 'o');
		$string		= array('x', 's', 'e', 'c');
		
		// get sql
		$sql	= $args[0];
		
		$sql	= str_replace('#__', $this->_prefix, $sql); // insert the prefix
		unset($args[0]);
		$args = array_values($args); // reset the indexes
		
		preg_match_all("/(\%[a-z]{1})/", $sql, $_matches);
		// check that the number of arguments matches the number of replaces in the sql
		if(count($_matches[0]) != count($args)) {
			die('the number of replacement markers doesn\'t match the number of arguments');
		}
		// loop through the arguments
		foreach($args as $key=>$value) {
			$s = str_replace('%', '', $_matches[0][$key]); // get the replacement marker type
			if(in_array($s, $float)) {
				$args[$key] = (float)$value;
			} elseif(in_array($s, $integer)) {
				$args[$key] = (int)$value;
			} elseif(in_array($s, $string)) {
				$args[$key] = $this->escape($value);
			}
		}
		return vsprintf($sql, $args);
		
	}
}

?>